package com.backend.modules.task.service.impl;

import com.backend.common.event.SubmissionCreatedEvent;
import com.backend.common.event.TaskSubmissionEvent;
import com.backend.common.exception.BusinessException;
import com.backend.common.utils.SecurityUtils;
import com.backend.common.utils.RedisUtils;
import com.backend.modules.notification.enums.NotificationType;
import com.backend.modules.notification.service.NotificationService;
import com.backend.modules.task.dto.SubmissionQueryDTO;
import com.backend.modules.task.dto.SubmissionReviewDTO;
import com.backend.modules.task.dto.TaskSubmissionDTO;
import com.backend.modules.task.entity.TaskSubmission;
import com.backend.modules.task.enums.SubmissionStatus;
import com.backend.modules.task.repository.TaskSubmissionRepository;
import com.backend.modules.task.service.TaskSubmissionService;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.Predicate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Service
@RequiredArgsConstructor
public class TaskSubmissionServiceImpl implements TaskSubmissionService {

    private final TaskSubmissionRepository submissionRepository;
    private final NotificationService notificationService;
    private final RedisUtils redisUtils;
    private final ApplicationEventPublisher eventPublisher;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void review(Long id, SubmissionReviewDTO dto) {
        // 获取提交记录
        TaskSubmission submission = submissionRepository.findById(id)
                .orElseThrow(() -> new BusinessException("提交记录不存在"));
        
        // 验证教师是否有权限审核
        if (!submission.getTask().getCreatorId().equals(SecurityUtils.getCurrentUserId())) {
            throw new BusinessException("无权审核此提交");
        }
        
        // 验证状态是否合法
        try {
            SubmissionStatus.valueOf(dto.getStatus());
        } catch (IllegalArgumentException e) {
            throw new BusinessException("无效的审核状态");
        }
        
        // 如果是拒绝状态，必须填写审核意见
        if (SubmissionStatus.REJECTED.name().equals(dto.getStatus()) 
                && (dto.getReviewComment() == null || dto.getReviewComment().trim().isEmpty())) {
            throw new BusinessException("拒绝时必须填写审核意见");
        }
        
        // 更新提交状态
        submission.setStatus(dto.getStatus());
        submission.setReviewComment(dto.getReviewComment());
        submission.setReviewTime(LocalDateTime.now());

        submissionRepository.save(submission);
        
        // 发送通知
        String title = SubmissionStatus.APPROVED.name().equals(dto.getStatus()) 
                ? "提交审核通过" : "提交审核不通过";
        String content = SubmissionStatus.APPROVED.name().equals(dto.getStatus())
                ? String.format("您提交的任务《%s》已审核通过", submission.getTask().getName())
                : String.format("您提交的任务《%s》审核不通过，原因：%s", 
                    submission.getTask().getName(), dto.getReviewComment());
        
        NotificationType type = SubmissionStatus.APPROVED.name().equals(dto.getStatus())
                ? NotificationType.SUBMISSION_APPROVED
                : NotificationType.SUBMISSION_REJECTED;
        
        notificationService.send(submission.getStudent().getId(), title, content, type, submission.getId());
        
        // 发布事件，触发邮件通知
        boolean isApproved = SubmissionStatus.APPROVED.name().equals(dto.getStatus());
        eventPublisher.publishEvent(new TaskSubmissionEvent(this, submission, isApproved));
        
        // 清除统计数据缓存
        redisUtils.delete("stats:admin:*");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchReview(List<Long> ids, SubmissionReviewDTO dto) {
        for (Long id : ids) {
            review(id, dto);
        }
    }

    @Override
    public TaskSubmission getById(Long id) {
        return submissionRepository.findById(id)
                .orElseThrow(() -> new BusinessException("提交记录不存在"));
    }

    @Override
    public Page<TaskSubmission> page(SubmissionQueryDTO query, Pageable pageable) {
        Specification<TaskSubmission> spec = (root, q, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            
            // 任务ID
            if (query.getTaskId() != null) {
                predicates.add(cb.equal(root.get("taskId"), query.getTaskId()));
            }
            
            // 学生姓名
            if (StringUtils.hasText(query.getStudentName())) {
                predicates.add(cb.like(
                    root.get("student").get("realName"), 
                    "%" + query.getStudentName() + "%"
                ));
            }
            
            // 学生学号
            if (StringUtils.hasText(query.getStudentNo())) {
                predicates.add(cb.like(
                    root.get("student").get("userCode"), 
                    "%" + query.getStudentNo() + "%"
                ));
            }
            
            // 提交状态
            if (query.getStatus() != null) {
                predicates.add(cb.equal(root.get("status"), query.getStatus().name()));
            }
            
            // 提交时间范围
            if (query.getStartTime() != null) {
                predicates.add(cb.greaterThanOrEqualTo(
                    root.get("submitTime"), 
                    query.getStartTime()
                ));
            }
            if (query.getEndTime() != null) {
                predicates.add(cb.lessThanOrEqualTo(
                    root.get("submitTime"), 
                    query.getEndTime()
                ));
            }
            
            return cb.and(predicates.toArray(new Predicate[0]));
        };
        
        return submissionRepository.findAll(spec, pageable);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(TaskSubmission submission) {
        submissionRepository.save(submission);
    }
    
    @Override
    @Async
    @Transactional(rollbackFor = Exception.class)
    public void aiAudit(Long submissionId) {
        // 获取提交记录
        TaskSubmission submission = getById(submissionId);
        
        // 发布事件，由AIAuditService监听并处理
        eventPublisher.publishEvent(new SubmissionCreatedEvent(this, submission));
    }
} 